package twilightforest.entity;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityFlying;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer;
import net.minecraft.entity.ai.EntityMoveHelper;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.World;
import twilightforest.TFAchievementPage;
import twilightforest.TFFeature;
import twilightforest.TFSounds;
import twilightforest.TwilightForestMod;

import java.util.Random;

public class EntityTFWraith extends EntityFlying implements IMob {
    public static final ResourceLocation LOOT_TABLE = new ResourceLocation(TwilightForestMod.ID, "entities/wraith");

    public EntityTFWraith(World world)
    {
        super(world);
    }

    @Override
    protected void initEntityAI() {
        this.tasks.addTask(4, new AIAttack(this));
        this.tasks.addTask(4, new AIFlyTowardsTarget(this));
        this.tasks.addTask(6, new AIRandomFly(this));
        this.tasks.addTask(7, new AILookAround(this));
        this.targetTasks.addTask(1, new EntityAIFindEntityNearestPlayer(this));
    }

    static class AIFlyTowardsTarget extends EntityAIBase {
        private final EntityTFWraith taskOwner;

        AIFlyTowardsTarget(EntityTFWraith wraith) {
            this.taskOwner = wraith;
            this.setMutexBits(1);
        }

        @Override
        public boolean shouldExecute() {
            return taskOwner.getAttackTarget() != null && !taskOwner.getMoveHelper().isUpdating();
        }

        @Override
        public void startExecuting() {
            // todo do we need a custom move helper like ghast as well?
            EntityLivingBase target = taskOwner.getAttackTarget();
            taskOwner.getMoveHelper().setMoveTo(target.posX, target.posY, target.posZ, 1.0F);
        }
    }

    // Similar to EntityAIAttackMelee but simpler (no pathfinding)
    static class AIAttack extends EntityAIBase {
        private final EntityTFWraith taskOwner;
        private int attackTick = 20;

        AIAttack(EntityTFWraith taskOwner) {
            this.taskOwner = taskOwner;
        }

        @Override
        public boolean shouldExecute() {
            EntityLivingBase target = taskOwner.getAttackTarget();

            return target != null
                    && target.getEntityBoundingBox().maxY > taskOwner.getEntityBoundingBox().minY
                    && target.getEntityBoundingBox().minY < taskOwner.getEntityBoundingBox().maxY
                    && taskOwner.getDistanceSqToEntity(target) <= 4.0D;
        }

        @Override
        public void updateTask() {
            if (attackTick > 0) {
                attackTick--;
            }
        }

        @Override
        public void resetTask() {
            attackTick = 20;
        }

        @Override
        public void startExecuting() {
            taskOwner.attackEntityAsMob(taskOwner.getAttackTarget());
            attackTick = 20;
        }
    }

    // [VanillaCopy] EntityGhast.AIRandomFly
    static class AIRandomFly extends EntityAIBase
    {
        private final EntityTFWraith parentEntity;

        public AIRandomFly(EntityTFWraith wraith)
        {
            this.parentEntity = wraith;
            this.setMutexBits(1);
        }

        @Override
        public boolean shouldExecute()
        {
            EntityMoveHelper entitymovehelper = this.parentEntity.getMoveHelper();

            if (!entitymovehelper.isUpdating())
            {
                return true;
            }
            else
            {
                double d0 = entitymovehelper.getX() - this.parentEntity.posX;
                double d1 = entitymovehelper.getY() - this.parentEntity.posY;
                double d2 = entitymovehelper.getZ() - this.parentEntity.posZ;
                double d3 = d0 * d0 + d1 * d1 + d2 * d2;
                return d3 < 1.0D || d3 > 3600.0D;
            }
        }

        @Override
        public boolean continueExecuting()
        {
            return false;
        }

        @Override
        public void startExecuting()
        {
            Random random = this.parentEntity.getRNG();
            double d0 = this.parentEntity.posX + (double)((random.nextFloat() * 2.0F - 1.0F) * 16.0F);
            double d1 = this.parentEntity.posY + (double)((random.nextFloat() * 2.0F - 1.0F) * 16.0F);
            double d2 = this.parentEntity.posZ + (double)((random.nextFloat() * 2.0F - 1.0F) * 16.0F);
            this.parentEntity.getMoveHelper().setMoveTo(d0, d1, d2, 1.0D);
        }
    }

    // [VanillaCopy] EntityGhast.AILookAround
    public static class AILookAround extends EntityAIBase
    {
        private final EntityTFWraith parentEntity;

        public AILookAround(EntityTFWraith wraith)
        {
            this.parentEntity = wraith;
            this.setMutexBits(2);
        }

        @Override
        public boolean shouldExecute()
        {
            return true;
        }

        @Override
        public void updateTask()
        {
            if (this.parentEntity.getAttackTarget() == null)
            {
                this.parentEntity.rotationYaw = -((float)MathHelper.atan2(this.parentEntity.motionX, this.parentEntity.motionZ)) * (180F / (float)Math.PI);
                this.parentEntity.renderYawOffset = this.parentEntity.rotationYaw;
            }
            else
            {
                EntityLivingBase entitylivingbase = this.parentEntity.getAttackTarget();
                double d0 = 64.0D;

                if (entitylivingbase.getDistanceSqToEntity(this.parentEntity) < 4096.0D)
                {
                    double d1 = entitylivingbase.posX - this.parentEntity.posX;
                    double d2 = entitylivingbase.posZ - this.parentEntity.posZ;
                    this.parentEntity.rotationYaw = -((float)MathHelper.atan2(d1, d2)) * (180F / (float)Math.PI);
                    this.parentEntity.renderYawOffset = this.parentEntity.rotationYaw;
                }
            }
        }
    }

	@Override
    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5D);
        
        // need to initialize damage since we're not an EntityMob
        this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE);
        this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(5.0D);
    }

    @Override
    public boolean canTriggerWalking()
    {
        return false;
    }

    // [VanillaCopy] EntityMob.attackEntityAsMob. This whole inheritance hierarchy makes me sad.
    @Override
    public boolean attackEntityAsMob(Entity entityIn) {
        float f = (float)this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue();
        int i = 0;

        if (entityIn instanceof EntityLivingBase)
        {
            f += EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), ((EntityLivingBase)entityIn).getCreatureAttribute());
            i += EnchantmentHelper.getKnockbackModifier(this);
        }

        boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), f);

        if (flag)
        {
            if (i > 0 && entityIn instanceof EntityLivingBase)
            {
                ((EntityLivingBase)entityIn).knockBack(this, (float)i * 0.5F, (double)MathHelper.sin(this.rotationYaw * 0.017453292F), (double)(-MathHelper.cos(this.rotationYaw * 0.017453292F)));
                this.motionX *= 0.6D;
                this.motionZ *= 0.6D;
            }

            int j = EnchantmentHelper.getFireAspectModifier(this);

            if (j > 0)
            {
                entityIn.setFire(j * 4);
            }

            if (entityIn instanceof EntityPlayer)
            {
                EntityPlayer entityplayer = (EntityPlayer)entityIn;
                ItemStack itemstack = this.getHeldItemMainhand();
                ItemStack itemstack1 = entityplayer.isHandActive() ? entityplayer.getActiveItemStack() : null;

                if (itemstack != null && itemstack1 != null && itemstack.getItem() instanceof ItemAxe && itemstack1.getItem() == Items.SHIELD)
                {
                    float f1 = 0.25F + (float)EnchantmentHelper.getEfficiencyModifier(this) * 0.05F;

                    if (this.rand.nextFloat() < f1)
                    {
                        entityplayer.getCooldownTracker().setCooldown(Items.SHIELD, 100);
                        this.world.setEntityState(entityplayer, (byte)30);
                    }
                }
            }

            this.applyEnchantments(this, entityIn);
        }

        return flag;
    }

    @Override
	public boolean attackEntityFrom(DamageSource damagesource, float i)
    {
        if(super.attackEntityFrom(damagesource, i))
        {
            Entity entity = damagesource.getEntity();
            if(getRidingEntity() == entity || getPassengers().contains(entity))
            {
                return true;
            }
            if (entity != this && entity instanceof EntityLivingBase) {
                setAttackTarget((EntityLivingBase) entity);
            }
            return true;
        } else
        {
            return false;
        }
    }
    
    @Override
	protected SoundEvent getAmbientSound()
    {
        return TFSounds.WRAITH;
    }

    @Override
	protected SoundEvent getHurtSound()
    {
        return TFSounds.WRAITH;
    }

    @Override
	protected SoundEvent getDeathSound()
    {
        return TFSounds.WRAITH;
    }

    @Override
    public ResourceLocation getLootTable() {
        return LOOT_TABLE;
    }

	@Override
	public void onDeath(DamageSource par1DamageSource) {
		super.onDeath(par1DamageSource);
		if (par1DamageSource.getSourceOfDamage() instanceof EntityPlayer) {
			((EntityPlayer)par1DamageSource.getSourceOfDamage()).addStat(TFAchievementPage.twilightHunter);
			// are we in a level 3 hill?
			int chunkX = MathHelper.floor(posX) >> 4;
			int chunkZ = MathHelper.floor(posZ) >> 4;
			if (TFFeature.getNearestFeature(chunkX, chunkZ, world) == TFFeature.hill3) {
				// award level 3 hill cheevo
				((EntityPlayer)par1DamageSource.getSourceOfDamage()).addStat(TFAchievementPage.twilightHill3);
			}
		}
	}
	
    // [VanillaCopy] Direct copy of EntityMob.isValidLightLevel
    protected boolean isValidLightLevel()
    {
        BlockPos blockpos = new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ);

        if (this.world.getLightFor(EnumSkyBlock.SKY, blockpos) > this.rand.nextInt(32))
        {
            return false;
        }
        else
        {
            int i = this.world.getLightFromNeighbors(blockpos);

            if (this.world.isThundering())
            {
                int j = this.world.getSkylightSubtracted();
                this.world.setSkylightSubtracted(10);
                i = this.world.getLightFromNeighbors(blockpos);
                this.world.setSkylightSubtracted(j);
            }

            return i <= this.rand.nextInt(8);
        }
    }

    @Override
    public boolean getCanSpawnHere()
    {
        return this.world.getDifficulty() != EnumDifficulty.PEACEFUL && this.isValidLightLevel() && super.getCanSpawnHere();
    }
}
